package com.loe.mvp.util.sp

import android.content.Context
import android.content.SharedPreferences
import org.json.JSONArray
import org.json.JSONObject
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

open class SpDelegate
{
    var sp: SharedPreferences? = null

    @JvmOverloads
    fun init(context: Context, name: String = "user", mode: Int = Context.MODE_PRIVATE)
    {
        sp = context.getSharedPreferences(name + this::class.java.name, mode)
        if (SpPublic.sp == null)
        {
            SpPublic.init(context)
            SpJsonPublic.init(context)
        }
    }

    /** 获取存储字符串  */
    fun getString(key: String, def: String = ""): String
    {
        return sp?.getString(key, def) ?: def
    }

    /** 录入存储字符串  */
    fun putString(key: String, value: String)
    {
        val editor = sp?.edit()
        editor?.putString(key, value)
        editor?.apply()
    }

    /** 获取存储整数  */
    fun getInt(key: String, def: Int = 0): Int
    {
        return sp?.getInt(key, def) ?: def
    }

    /** 录入存储整数  */
    fun putInt(key: String, value: Int)
    {
        val editor = sp?.edit()
        editor?.putInt(key, value)
        editor?.apply()
    }

    /** 获取存储长整数  */
    fun getLong(key: String, def: Long = 0): Long
    {
        return sp?.getLong(key, def) ?: def
    }

    /** 录入存储长整数  */
    fun putLong(key: String, value: Long)
    {
        val editor = sp?.edit()
        editor?.putLong(key, value)
        editor?.apply()
    }

    /** 获取存储小数  */
    fun getFloat(key: String, def: Float = 0f): Float
    {
        return sp?.getFloat(key, def) ?: def
    }

    /** 录入存储小数  */
    fun putFloat(key: String, value: Float)
    {
        val editor = sp?.edit()
        editor?.putFloat(key, value)
        editor?.apply()
    }

    /** 获取存储双小数  */
    fun getDouble(key: String, def: Double = 0.0): Double
    {
        return try
        {
            sp?.getString(key, def.toString())!!.toDouble()
        } catch (e: Exception)
        {
            def
        }
    }

    /** 录入存储双小数  */
    fun putDouble(key: String, value: Double)
    {
        val editor = sp?.edit()
        editor?.putString(key, value.toString() + "")
        editor?.apply()
    }

    /** 获取存储布尔值  */
    fun getBoolean(key: String, def: Boolean = false): Boolean
    {
        return sp?.getBoolean(key, def) ?: def
    }

    /** 录入存储布尔值  */
    fun putBoolean(key: String, value: Boolean)
    {
        val editor = sp?.edit()
        editor?.putBoolean(key, value)
        editor?.apply()
    }

    /** 获取存储json  */
    fun getJson(key: String): JSONObject
    {
        try
        {
            return JSONObject(sp?.getString(key, ""))
        } catch (e: Exception)
        {
        }
        return JSONObject()
    }

    /** 录入存储json  */
    fun putJson(key: String, value: JSONObject)
    {
        val editor = sp?.edit()
        editor?.putString(key, value.toString())
        editor?.apply()
    }

    /** 获取存储json数组  */
    fun getJsonArray(key: String): JSONArray
    {
        try
        {
            return JSONArray(sp?.getString(key, ""))
        } catch (e: Exception)
        {
        }
        return JSONArray()
    }

    /** 录入存储json数组  */
    fun putJsonArray(key: String, value: JSONArray)
    {
        val editor = sp?.edit()
        editor?.putString(key, value.toString())
        editor?.apply()
    }

    fun clear()
    {
        val editor = sp?.edit()
        editor?.clear()
        editor?.apply()
    }

    /***************************** 属性委托  ***************************/

    fun string(def: String = "") = object : ReadWriteProperty<SpDelegate, String>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): String
        {
            return getString(property.name, def)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: String)
        {
            putString(property.name, value)
        }
    }

    /** @param second 过期秒数 */
    fun stringExp(second: Number, def: String = "") = object : ReadWriteProperty<SpDelegate, String>
    {
        private val millis = second.toDouble() * 1000

        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): String
        {
            val saveTime = getLong(property.name + "_saveTime")
            return if (System.currentTimeMillis() - saveTime > millis)
            {
                def
            } else
            {
                getString(property.name, def)
            }
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: String)
        {
            putString(property.name, value)
            putLong(property.name + "_saveTime", System.currentTimeMillis())
        }
    }

    fun int(def: Int = 0) = object : ReadWriteProperty<SpDelegate, Int>
    {

        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): Int
        {
            return getInt(property.name, def)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: Int)
        {
            putInt(property.name, value)
        }
    }

    fun long(def: Long = 0L) = object : ReadWriteProperty<SpDelegate, Long>
    {

        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): Long
        {
            return getLong(property.name, def)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: Long)
        {
            putLong(property.name, value)
        }
    }

    fun float(def: Float = 0.0f) = object : ReadWriteProperty<SpDelegate, Float>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): Float
        {
            return getFloat(property.name, def)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: Float)
        {
            putFloat(property.name, value)
        }
    }

    fun double(def: Double = 0.0) = object : ReadWriteProperty<SpDelegate, Double>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): Double
        {
            return getDouble(property.name, def)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: Double)
        {
            putDouble(property.name, value)
        }
    }

    fun boolean(def: Boolean = false) = object : ReadWriteProperty<SpDelegate, Boolean>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): Boolean
        {
            return getBoolean(property.name, def)
        }

        override fun setValue(
            thisRef: SpDelegate,
            property: KProperty<*>,
            value: Boolean
        )
        {
            putBoolean(property.name, value)
        }
    }

    fun jsonArray() = object : ReadWriteProperty<SpDelegate, JSONArray>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): JSONArray
        {
            return getJsonArray(property.name)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: JSONArray)
        {
            putJsonArray(property.name, value)
        }
    }

    fun json() = object : ReadWriteProperty<SpDelegate, JSONObject>
    {
        override fun getValue(thisRef: SpDelegate, property: KProperty<*>): JSONObject
        {
            return getJson(property.name)
        }

        override fun setValue(thisRef: SpDelegate, property: KProperty<*>, value: JSONObject)
        {
            putJson(property.name, value)
        }
    }
}